package com.zoweunion.mechanic.service.base.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserUserinfoShareResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.vdurmont.emoji.EmojiParser;
import com.zoweunion.mechanic.dao.base.UserDao;
import com.zoweunion.mechanic.dao.base.WxUserInfoDao;
import com.zoweunion.mechanic.im.HttpClient;
import com.zoweunion.mechanic.im.ImConfig;
import com.zoweunion.mechanic.model.User;
import com.zoweunion.mechanic.model.WxUserInfo;
import com.zoweunion.mechanic.plugins.redis.RedisUtil;
import com.zoweunion.mechanic.service.app.SpeedyLoginService;
import com.zoweunion.mechanic.service.base.UserService;
import com.zoweunion.mechanic.util.*;
import com.zoweunion.mechanic.util.constants.Constants;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service(value = "userService")
@Transactional()
@SuppressWarnings("unchecked")
public class UserServiceImpl implements UserService {

	public static final String USER_PRE = "USER_PRE:";
	public static final String IM_PRE = "IM_PRE:";
	public static final long EXPIRE_TIME = 3600 * 24;
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private UserDao userDao;
	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private ImConfig imConfig;
	@Autowired
	private WxUserInfoDao wxUserInfoDao;
	@Autowired
	private SpeedyLoginService speedyLoginService;

	/**
	 * 根据username查询用户名 密码 同时将数据缓存到redis中
	 */
	@Override
	@Transactional(readOnly = true)
	public User getUserByAccount(String user_account) {
		// 1.先从redis中查询数据 查询到则返回,查询不到再查询数据库
		//User redisUser = JSONObject.parseObject(redisUtil.get(USER_PRE + user_account) + "", User.class);
//		if (redisUser != null) {
//			return redisUser;
//		}
		// 2.redis中没有数据则查询数据库
		Map<String, String> reqMap = new HashMap<>();
		reqMap.put("user_account", user_account);
		Map<String, String> resultMap = new HashMap<>();
		resultMap = userDao.getUser(reqMap);
		User dbUser = new User();
		if (null != resultMap) {
			dbUser.setId(resultMap.get("id"));
			dbUser.setR_id(resultMap.get("r_id"));
			dbUser.setRemaining_sum(resultMap.get("remaining_sum"));
			dbUser.setS_id(resultMap.get("s_id"));
			dbUser.setUser_account(resultMap.get("user_account"));
			dbUser.setUser_name(resultMap.get("user_name"));
			dbUser.setUser_password(resultMap.get("user_password"));
			dbUser.setOpen_id(resultMap.get("open_id"));
			dbUser.setAli_user_id(resultMap.get("ali_user_id"));
			dbUser.setIntegration(Integer.valueOf(resultMap.get("integration")));
			dbUser.setCredit_limit(resultMap.get("credit_limit"));
			dbUser.setMobile_phone(resultMap.get("mobile_phone"));
			dbUser.setWarehouse_id(resultMap.get("warehouse_id"));
			// 3.将数据库查询到的数据放入redis
			//redisUtil.set(USER_PRE + user_account, JSONObject.toJSONString(dbUser), EXPIRE_TIME);
			return dbUser;
		}else {

			return null;

		}

	}

	/**
	 * 添加用户修改密码的历史记录
	 */
	@Override
	public void recordUserPassword(Map<String, Object> reqObj) {

		reqObj.put("id",UuidUtil.get32UUID());

		userDao.recordUserPassword(reqObj);
	}

	@Override
	public Map<String, Object> getUserById(String id) {
		return userDao.getUserById(id);
	}

	/**
	 * 根据username查询用户具体信息
	 */
	@Override
	@Transactional(readOnly = true)
	public Map<String, Object> getUserInfoByAccount(String user_account) {
		Map<String, String> reqMap = new HashMap<>();
		reqMap.put("user_account", user_account);
		Map<String, Object> userInfo = userDao.getUserInfo(reqMap);
		if (userInfo != null) {
			// 获取我的发布数量和获取我的收藏
			Map totalMap = userDao.getMyCollectionAndPublishTotal(userInfo.get("id").toString());
			userInfo.put("collectionTotal", totalMap.get("collectionTotal"));
			userInfo.put("publishTotal", totalMap.get("publishTotal"));
		}
		return userInfo;
	}

	/**
	 * 根据username查询用户具体信息
	 */
	@Override
	@Transactional(readOnly = true)
	public Map<String, Object> getUserInfoById(String userId) {
		return userDao.getUserInfoById(userId);
	}

	/**
	 * 根据用户名查询用户数量
	 */
	@Override
	@Transactional(readOnly = true)
	public int checkExistForUser(Object object) {
		return userDao.countUserByAccount(object.toString());
	}

	/**
	 * 注册用户
	 */
	@Override
	public String doRegister(Map<String, Object> reqObj) {
		Map<String,String> map = new HashMap<String, String>();
		Map<String, Object> resultMap = new HashMap<>();
		String nonce = UuidUtil.get32UUID();
		String signTimestamp = String.valueOf(System.currentTimeMillis());
		String signature = "";
		String result = "";
		// 补充用户属性
		String uuid = UuidUtil.get32UUID();
		map.put("userId", uuid);
		map.put("name", reqObj.get("user_name").toString());
		//String u_id = user.getId();
		reqObj.put("id", uuid);
		if (reqObj.get("update_user") == null) {
			reqObj.put("update_user", uuid);
		}
		if (reqObj.get("create_user") == null) {
			reqObj.put("create_user", uuid);
		}
		try {
			signature = Sha1.shaEncode(imConfig.getAppSecret()+nonce+signTimestamp);
			result = HttpClient.send(imConfig.getUrl(), map, imConfig.getEncoding(), imConfig.getAppKey(), nonce, signTimestamp, signature);
			resultMap = JSONObject.parseObject(result,Map.class);
			String code = resultMap.get("code").toString();
			Object object = resultMap.get("token");
			if ("200".equals(code)) {
				redisUtil.set(IM_PRE+uuid+"token",object,EXPIRE_TIME);
				reqObj.put("token", object.toString());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		reqObj.put("user_password", MD5.md5(reqObj.get("user_password").toString()));
		// 如果服务商为空,则用户角色为游客
		if (reqObj.get("s_id") == null || "".equals(reqObj.get("s_id")) || reqObj.get("r_id") == null
				|| "".equals(reqObj.get("r_id"))) {
			reqObj.put("r_id", Constants.ROLE_YK);
			reqObj.put("user_name", Tool.secretMobilePhone(reqObj.get("mobile_phone").toString()));  // 游客的设置用户名为手机号,手机号中间部分设置为✳
		}else{
			// 如果角色不为空
			String userNo = generateUserNo(reqObj.get("r_id").toString());
			reqObj.put("userNo",userNo);
		}
		//此处由于前台没有开发,无法传参数后台会报错,为了保证后台能够正常运行,所以此处将area与speciality两个字段都赋予null.后期要改
		if (!reqObj.containsKey("area")) {
			reqObj.put("area", reqObj.get("area"));
		}
		if (!reqObj.containsKey("speciality")) {
			reqObj.put("speciality", reqObj.get("speciality"));
		}
		if (reqObj.get("credit_limit") == null || StringUtils.isBlank(reqObj.get("credit_limit").toString())){
			reqObj.put("credit_limit", 0);
		}
		if (reqObj.get("remaining_sum") == null || StringUtils.isBlank(reqObj.get("remaining_sum").toString())){
			reqObj.put("remaining_sum", 0);
		}
		if (reqObj.get("user_name") != null) {
			reqObj.put("pinyin_head", PinyinUtil.convertToPinyinIc(reqObj.get("user_name").toString()));
		}
		userDao.insertUser(reqObj);
		return uuid;
	}

	/**
	 * 修改用户
	 */
	@Override
	public void update(Map<String, Object> userInfo) {
		// 判断是否为删除或者禁用操作 是则删除缓存中的数据
		//if (userInfo.get("status") != null && (int) userInfo.get("status") == 2
				//|| userInfo.get("delete_flag") != null && (int) userInfo.get("delete_flag") == 1) {
			//redisUtil.remove(USER_PRE + userInfo.get("user_account"));
		//}
		if (userInfo.get("user_password") != null && !"".equals(userInfo.get("user_password"))) {
			userInfo.put("user_password", MD5.md5(userInfo.get("user_password").toString()));
		}
		if (userInfo.get("user_name") != null) {
			userInfo.put("pinyin_head", PinyinUtil.convertToPinyinIc(userInfo.get("user_name").toString()));
		}
		userDao.updateUser(userInfo);
	}

	/**
	 * 根据user_account查询用户相应的权限
	 *
	 * @param account
	 * @return
	 */
	@Override
	@Transactional(readOnly = true)
	public List<String> getPermissionsByAccount(String account) {
		return userDao.getPermissionsByAccount(account);
	}

	@Override
	@Transactional(readOnly = true)
	public Map<String, Object> getAllUserByPage(Map<String, Object> reqMap) {
		// 设置分页的limit和offset
		Map<String, Object> pageMap = Page.appPage(reqMap.get("pageSize").toString(),
				reqMap.get("currentPage").toString());
		reqMap.put("pageSize", pageMap.get("limit"));
		reqMap.put("currentPage", pageMap.get("offset"));
		int limit = Integer.valueOf(pageMap.get("limit").toString());
		// 查询总记录数
		int total = userDao.getAllUserByCount(reqMap);
		List<Map<String, Object>> list = userDao.getAllUserByPage(reqMap);
		int totalPage = total%limit == 0 ? total/limit : (total/limit+1);
		// 包装结果集 总条数 总页数 数据集
		HashMap<String, Object> resultMap = new HashMap<String, Object>();
		resultMap.put("total", total);
		resultMap.put("list", list);
		resultMap.put("totalPage", totalPage);
		return resultMap;
	}

	@Override
	@Transactional(readOnly = true)
	public List<Map<String, Object>> getUser(Map<String, Object> reqMap) {
		return userDao.getUserByRole(reqMap);
	}

	@Override
	@Transactional(readOnly = true)
	public List<Map<String, Object>> getUserWithAuth() {

		return userDao.getUserWithAuth();
	}

	@Override
	public Map<String, Object> getAuthInfo(String user_account) {

		return userDao.getAuthInfo(user_account);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean unbindWx(User user, Integer type) throws MyException {
		Map<String, Object> reqMap = new HashMap<>();
		reqMap.put("id", user.getId());
		reqMap.put("type", type);
		// user解绑
		userDao.unbindWxOrAlipay(reqMap);
		if (WxUserInfo.TYPE_WX.equals(type)) {
			//解绑微信
			return this.logicDeleteByOpenid(user.getOpen_id());
		} else if (WxUserInfo.TYPE_ALIPAY.equals(type)) {
			//解绑支付宝
			return this.logicDeleteByOpenid(user.getAli_user_id());
		} else {
			throw new MyException(Constants.CODE_HANDEL_FAILED, "不支持的解绑方式");
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean bindWx(User user, Integer type, String authCode) throws MyException, AlipayApiException {
		if (WxUserInfo.TYPE_WX.equals(type)) {
			// 微信绑定
			// 获取token信息
			Map<String, Object> tokenInfoMap = ThirdPartyAuthUtil.getAccessTokenWX(authCode);
			// 获取微信用户信息
			WxUserInfo wxUserInfo = ThirdPartyAuthUtil.getUserInfoWX(tokenInfoMap.get("access_token").toString(), tokenInfoMap.get("openid").toString());
			//判断是否已经被绑定
			Map<String, Object> wechatInfoMap = speedyLoginService.userInfoWithWxId(wxUserInfo.getOpenid(), WxUserInfo.TYPE_WX);
			if (Boolean.valueOf(wechatInfoMap.get("flag").toString())) {
				throw new MyException(Constants.CODE_ACCESS_PROHIBITED, "此微信号已经被绑定");
			}
			user.setOpen_id(wxUserInfo.getOpenid());
			this.bindWxWrap(user, type, wxUserInfo.getOpenid());
			// 保存微信信息
			wxUserInfo.setUser_id(user.getId());
			this.saveWxUserInfo(wxUserInfo);
		} else if (WxUserInfo.TYPE_ALIPAY.equals(type)) {
			// 支付宝绑定
			// 获取支付宝token信息
			AlipaySystemOauthTokenResponse tokenResponse = ThirdPartyAuthUtil.getAccessTokenAlipay(authCode);
			// 获取支付宝用户信息
			AlipayUserUserinfoShareResponse userInfoAlipay = ThirdPartyAuthUtil.getUserInfoAlipay(tokenResponse.getAccessToken());
			WxUserInfo wxUserInfo = ThirdPartyAuthUtil.alipayUserInfoToWxUserInfo(userInfoAlipay);
			//判断是否已经被绑定
			Map<String, Object> userInfoMap = speedyLoginService.userInfoWithWxId(wxUserInfo.getOpenid(), WxUserInfo.TYPE_ALIPAY);
			if (Boolean.valueOf(userInfoMap.get("flag").toString())) {
				throw new MyException(Constants.CODE_ACCESS_PROHIBITED, "此支付宝账号已经被绑定");
			}
			user.setAli_user_id(wxUserInfo.getOpenid());
			this.bindWxWrap(user, type, wxUserInfo.getOpenid());
			// 保存微信信息
			wxUserInfo.setUser_id(user.getId());
			this.saveWxUserInfo(wxUserInfo);
		} else {
			throw new MyException(Constants.CODE_ACCESS_PROHIBITED, "不支持的绑定方式");
		}
		return true;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean bindWxWrap(User user, Integer type, String openid) {
		// 绑定
		Map<String, Object> reqMap = new HashMap<>();
		reqMap.put("id", user.getId());
		if (WxUserInfo.TYPE_WX.equals(type)) {
			// 解绑
            if (StringUtils.isNotBlank(user.getOpen_id())) {
                this.logicDeleteByOpenid(user.getOpen_id());
            }
			reqMap.put("open_id", openid);
		} else if (WxUserInfo.TYPE_ALIPAY.equals(type)) {
			// 解绑
            if (StringUtils.isNotBlank(user.getAli_user_id())) {
			    this.logicDeleteByOpenid(user.getAli_user_id());
            }
			reqMap.put("ali_user_id", openid);
		}
		userDao.bindWxOrAlipay(reqMap);
		return true;
	}

	@Override
	public WxUserInfo getWxUserInfoByOpenid(String openid) {
		return wxUserInfoDao.getWxUserInfoByOpenid(openid);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveWxUserInfo(WxUserInfo wxUserInfo) {
		if (StringUtils.isNotBlank(wxUserInfo.getNickname())) {
			wxUserInfo.setNickname(EmojiParser.removeAllEmojis(wxUserInfo.getNickname()));
		}
		wxUserInfo.setId(UuidUtil.get32UUID());
		return wxUserInfoDao.saveWxUserInfo(wxUserInfo) > 0;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean logicDeleteByOpenid(String openid) {
		if (StringUtils.isBlank(openid)) {
			return false;
		}
		WxUserInfo wxUserInfo = new WxUserInfo();
		wxUserInfo.setOpenid(openid);
		return wxUserInfoDao.logicDeleteByOpenidOrId(wxUserInfo) > 0;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean logicDeleteById(String id) {
		if (StringUtils.isBlank(id)) {
			return false;
		}
		WxUserInfo wxUserInfo = new WxUserInfo();
		wxUserInfo.setId(id);
		return wxUserInfoDao.logicDeleteByOpenidOrId(wxUserInfo) > 0;
	}

	@Override
	public Map<String, Object> myBindWx(Map<String, Object> userMap) {
		Map<String, Object> userInfo = new HashMap<>(3);
		WxUserInfo userInfoWx = null;
		WxUserInfo userInfoAlipay = null;
		if (userMap.get("open_id") != null && StringUtils.isNotBlank(userMap.get("open_id").toString())) {
			userInfoWx = wxUserInfoDao.getWxUserInfoByOpenid(userMap.get("open_id").toString());
		}
		if (userMap.get("ali_user_id") != null && StringUtils.isNotBlank(userMap.get("ali_user_id").toString())) {
			userInfoAlipay = wxUserInfoDao.getWxUserInfoByOpenid(userMap.get("ali_user_id").toString());
		}
		// 给ios端使用
		if (userInfoWx == null) {
			userInfoWx = new WxUserInfo();
		}
		if (userInfoAlipay == null) {
			userInfoAlipay = new WxUserInfo();
		}
		userInfo.put("userInfoWx", userInfoWx);
		userInfo.put("userInfoAlipay", userInfoAlipay);
		return userInfo;
	}

	@Override
	public Map<String, Object> myBindWx(User user) {
		Map<String, Object> userInfo = new HashMap<>(3);
		WxUserInfo userInfoWx = null;
		WxUserInfo userInfoAlipay = null;
		if (StringUtils.isNotBlank(user.getOpen_id())) {
			userInfoWx = wxUserInfoDao.getWxUserInfoByOpenid(user.getOpen_id());
		}
		if (StringUtils.isNotBlank(user.getAli_user_id())) {
			userInfoAlipay = wxUserInfoDao.getWxUserInfoByOpenid(user.getAli_user_id());
		}
		// 给ios端使用
		if (userInfoWx == null) {
			userInfoWx = new WxUserInfo();
		}
		if (userInfoAlipay == null) {
			userInfoAlipay = new WxUserInfo();
		}
		userInfo.put("userInfoWx", userInfoWx);
		userInfo.put("userInfoAlipay", userInfoAlipay);
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveNotFoundWx(WxUserInfo wxUserInfo) {
		WxUserInfo wxUserInfoS = this.getWxUserInfoByOpenid(wxUserInfo.getOpenid());
		if (wxUserInfoS == null) {
			this.saveWxUserInfo(wxUserInfo);
		}
		return true;
	}

	@Override
	public void updatePassWord(Map reqMap) {
		userDao.updatePassword(reqMap);
	}

	@Override
	public PageInfo getServerByArea(Map<String, Object> paraMap) {
		int currentPage = Orgin.getIntValue(paraMap, "currentPage");
		int pageSize = Orgin.getIntValue(paraMap, "pageSize");
		PageHelper.startPage(currentPage, pageSize);
		List<Map<String, Object>> serverList = userDao.getServerByArea(paraMap);
		return new PageInfo(serverList);
	}

	@Override
	public boolean logout(Map reqMap) {
		userDao.logout(reqMap);
		if(userDao.selectDelete(reqMap) == 1){
			return true;
		}
		return false;
	}

	@Override
	public PageInfo getExamineUserList(Map reqMap) {
		int currentPage = Orgin.getIntValue(reqMap, "currentPage");
		int pageSize = Orgin.getIntValue(reqMap, "pageSize");
		PageHelper.startPage(currentPage, pageSize);
	    List<Map<String,Object>> userList = userDao.getExamineUserList(reqMap);
		return new PageInfo(userList);
	}

	@Override
	public void approveExamineUser(Map reqMap) {
		userDao.approveExamineUser(reqMap);
	}

	@Override
	public void refuseExamineUser(Map reqMap) {
		userDao.refuseExamineUser(reqMap);
	}


	/**
	 * 根据用户的角色类型来生成对应的用户编号
	 * @param roleId
	 * @return
	 */
	public String generateUserNo(String roleId){

		String newNoString = generateNewNoByRoleId(roleId);

		if(Constants.ROLE_KF.equals(roleId)){
			return "KF"+newNoString;
		}else if(Constants.ROLE_TZ.equals(roleId)){
			return "TZ"+newNoString;
		}else if(Constants.ROLE_XG.equals(roleId)){
			return "XG"+newNoString;
		}else if(Constants.ROLE_CG.equals(roleId)){
			return "CG"+newNoString;
		}else if(Constants.ROLE_CZ.equals(roleId)){
			return "CZ"+newNoString;
		}else if(Constants.ROLE_SJ.equals(roleId)){
			return "SJ"+newNoString;
		}else if(Constants.ROLE_GLY.equals(roleId)){
			return "GL"+newNoString;
		}else if(Constants.ROLE_GG.equals(roleId)){
			return "GG"+newNoString;
		}else if(Constants.ROLE_YK.equals(roleId)){
			return "YK"+newNoString;
		}else if(Constants.ROLE_XS.equals(roleId)){
			return "XS"+newNoString;
		}else{
			return "";
		}
	}

	/**
	 * 根据roleId生成最新的用户编号
	 * @param roleId
	 * @return
	 */
	public String generateNewNoByRoleId(String roleId){
		// 查询角色最新的no,加1生成新的no
		String latestUserNo =  userDao.getLatestUserNoByRoleId(roleId);
		String newNoString = "001";
		if(StringUtils.isNotBlank(latestUserNo)){
			Integer latestNo =  Integer.valueOf(latestUserNo.substring(2,latestUserNo.length()));
			Integer newNo = latestNo+1;

			// 格式化为 KF001
			if(newNo<10){
				newNoString = "00"+newNo;
			}else if(newNo<100){
				newNoString = "0"+newNo;
			}else{
				newNoString = ""+ newNo;
			}
		}

		return newNoString;
	}

}
